package com.junhong.forum.service;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import javax.annotation.PostConstruct;
import javax.ejb.ConcurrencyManagement;
import javax.ejb.ConcurrencyManagementType;
import javax.ejb.EJB;
import javax.ejb.Lock;
import javax.ejb.LockType;
import javax.ejb.Schedule;
import javax.ejb.Singleton;
import javax.ejb.Timeout;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Named;

import com.junhong.forum.entity.ForumCategory;
import com.junhong.forum.entity.ForumCategoryComparator;
import com.junhong.forum.entity.ForumThread;
import com.junhong.forum.entity.ThreadDashBoard;
import com.junhong.forum.entity.ThreadDashBoardComparator;
import com.junhong.util.CommonUtil;

/**
 * Session Bean implementation class DashBoardService
 */

@Named
@ApplicationScoped
@Singleton
@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
@TransactionManagement(TransactionManagementType.CONTAINER)
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
@Lock(LockType.READ)
public class ThreadDashBoardCacheService {

	@EJB
	private CategoryServiceSingleton					categoryEjb;
	private Map<ForumCategory, List<ThreadDashBoard>>	categoryThreadsMap						= new ConcurrentHashMap<ForumCategory, List<ThreadDashBoard>>();
	private ForumCategory[]								allCategoryArray						= null;
	@EJB
	private GenericCRUDService<ThreadDashBoard>			genericCRUDService;

	@EJB
	private ThreadEjb									threadEjb;

	private List<ThreadDashBoard>						allDashBoardThreads						= null;
	private List<ForumThread>							mostRecentThreadList					= new ArrayList<ForumThread>();
	private List<ForumThread>							trendingPopularThreadList				= new ArrayList<ForumThread>();
	private List<ThreadDashBoard>						allDashBoardThreadsDBToday				= new ArrayList<ThreadDashBoard>();
	private List<ThreadDashBoard>						allDashBoardThreadsDBYesterday			= new ArrayList<ThreadDashBoard>();
	private List<ThreadDashBoard>						allDashBoardThreadsDBBeforeYesterday	= new ArrayList<ThreadDashBoard>();
	private List<ThreadDashBoard>						allDashBoardThreadsDBOlder				= new ArrayList<ThreadDashBoard>();
	private Date										currDate								= null;

	/**
	 * Default constructor.
	 */
	public ThreadDashBoardCacheService() {
		// TODO Auto-generated constructor stub
	}

	@PostConstruct
	public void init() {

		categoryThreadsMap.clear();
		allDashBoardThreads = genericCRUDService.findAll(ThreadDashBoard.class);

		int categoryId = -999999;
		int tempCategoryId = 0;
		List<ThreadDashBoard> dashbaords = null;
		ForumCategory category = null;
		for (ThreadDashBoard db : allDashBoardThreads) {
			// check the CategoryID is changed
			tempCategoryId = db.getCategoryId();
			if (categoryId != tempCategoryId) {
				categoryId = tempCategoryId;
				dashbaords = new ArrayList<ThreadDashBoard>();
				category = categoryEjb.getForumCategoryById(tempCategoryId);
				if (category != null) {
					categoryThreadsMap.put(category, dashbaords);
				}

				dashbaords.add(db);
			} else {
				dashbaords.add(db);
			}
		}

		// populate category name array.
		Set<ForumCategory> result = categoryThreadsMap.keySet();
		List<ForumCategory> resultList = new ArrayList<ForumCategory>();
		resultList.addAll(result);
		Collections.sort(resultList, new ForumCategoryComparator());
		this.allCategoryArray = new ForumCategory[resultList.size()];
		resultList.toArray(allCategoryArray);

		// get the most recent threads
		// mostRecentThreadList = threadEjb.getMostRecentThread(15);

		// get the most popular threads
		trendingPopularThreadList = threadEjb.getTrendingPopularThread(8, 3);

		// sort the list by createTime
		Collections.sort(allDashBoardThreads, Collections.reverseOrder(new ThreadDashBoardComparator()));

		// populate today/yesterday/older dealdashboard
		Date currDateTime = CommonUtil.getESTDate(new Date());
		this.currDate = new Date(currDateTime.getYear(), currDateTime.getMonth(), currDateTime.getDate());
		Calendar cal = Calendar.getInstance();
		cal.setTime(this.currDate);
		cal.add(Calendar.DATE, -1);
		Date yesterday = cal.getTime();
		cal.add(Calendar.DATE, -1);
		Date theDayBeforeYesterday = cal.getTime();
		allDashBoardThreadsDBToday.clear();
		allDashBoardThreadsDBYesterday.clear();
		allDashBoardThreadsDBBeforeYesterday.clear();
		allDashBoardThreadsDBOlder.clear();
		for (ThreadDashBoard tdb : allDashBoardThreads) {
			if (tdb.getCreateTime().after(currDate)) {
				allDashBoardThreadsDBToday.add(tdb);
			} else if (tdb.getCreateTime().after(yesterday)) {
				allDashBoardThreadsDBYesterday.add(tdb);
			} else if (tdb.getCreateTime().after(theDayBeforeYesterday)) {
				allDashBoardThreadsDBBeforeYesterday.add(tdb);
			} else {
				// keep only 20 records
				if (allDashBoardThreadsDBOlder.size() >= 20) {
					break;
				} else {
					allDashBoardThreadsDBOlder.add(tdb);
				}
			}
		}

	}

	@Timeout
	@Schedule(dayOfMonth = "*", month = "*", year = "*", second = "0", minute = "0/10", hour = "*", persistent = false)
	public void refreshCache() {
		init();

	}

	/**
	 * @return the categoryThreadsMap
	 */
	public Map<ForumCategory, List<ThreadDashBoard>> getCategoryThreadsMap() {
		return categoryThreadsMap;
	}

	/**
	 * @param categoryThreadsMap
	 *            the categoryThreadsMap to set
	 */
	public void setCategoryThreadsMap(Map<ForumCategory, List<ThreadDashBoard>> categoryThreadsMap) {
		this.categoryThreadsMap = categoryThreadsMap;
	}

	public List<ThreadDashBoard> getDashBoards(ForumCategory category) {
		if (category != null) {
			return categoryThreadsMap.get(category);
		} else {
			return null;
		}

	}

	public int getCategoryId(ForumCategory category) {
		if (category == null) {
			return 0;
		}
		List<ThreadDashBoard> threadDashBoards = getDashBoards(category);
		if (threadDashBoards != null && !threadDashBoards.isEmpty()) {
			return threadDashBoards.get(0).getCategoryId();
		} else {
			return 0;
		}
	}

	/**
	 * @return the allCategoryArray
	 */
	public ForumCategory[] getAllCategoryArray() {
		return allCategoryArray;
	}

	/**
	 * @param allCategoryArray
	 *            the allCategoryArray to set
	 */
	public void setAllCategoryArray(ForumCategory[] allCategoryArray) {
		this.allCategoryArray = allCategoryArray;
	}

	public List<ThreadDashBoard> getAllDashBoardThreads() {
		return allDashBoardThreads;
	}

	public void setAllDashBoardThreads(List<ThreadDashBoard> allDashBoardThreads) {
		this.allDashBoardThreads = allDashBoardThreads;
	}

	/*
	 * public List<ForumThread> getMostRecentThreadList() { return
	 * mostRecentThreadList; }
	 * 
	 * public void setMostRecentThreadList(List<ForumThread>
	 * mostRecentThreadList) { this.mostRecentThreadList = mostRecentThreadList;
	 * }
	 */
	public List<ForumThread> getTrendingPopularThreadList() {
		return trendingPopularThreadList;
	}

	public void setTrendingPopularThreadList(List<ForumThread> trendingPopularThreadList) {
		this.trendingPopularThreadList = trendingPopularThreadList;
	}

	public List<ThreadDashBoard> getAllDashBoardThreadsDBToday() {
		return allDashBoardThreadsDBToday;
	}

	public void setAllDashBoardThreadsDBToday(List<ThreadDashBoard> allDashBoardThreadsDBToday) {
		this.allDashBoardThreadsDBToday = allDashBoardThreadsDBToday;
	}

	public List<ThreadDashBoard> getAllDashBoardThreadsDBYesterday() {
		return allDashBoardThreadsDBYesterday;
	}

	public void setAllDashBoardThreadsDBYesterday(List<ThreadDashBoard> allDashBoardThreadsDBYesterday) {
		this.allDashBoardThreadsDBYesterday = allDashBoardThreadsDBYesterday;
	}

	public List<ThreadDashBoard> getAllDashBoardThreadsDBOlder() {
		return allDashBoardThreadsDBOlder;
	}

	public void setAllDashBoardThreadsDBOlder(List<ThreadDashBoard> allDashBoardThreadsDBOlder) {
		this.allDashBoardThreadsDBOlder = allDashBoardThreadsDBOlder;
	}

	public Date getCurrDate() {
		return currDate;
	}

	public void setCurrDate(Date currDate) {
		this.currDate = currDate;
	}

	public List<ThreadDashBoard> getAllDashBoardThreadsDBBeforeYesterday() {
		return allDashBoardThreadsDBBeforeYesterday;
	}

	public void setAllDashBoardThreadsDBBeforeYesterday(List<ThreadDashBoard> allDashBoardThreadsDBBeforeYesterday) {
		this.allDashBoardThreadsDBBeforeYesterday = allDashBoardThreadsDBBeforeYesterday;
	}

}
